package org.dreamwork.jasmine2.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class Tag {
    protected String prefix;
    protected String name;
    protected HashMap<String, String> attributes;
    protected HashMap<String, String> attributesIgnoreCase;
    protected ArrayList<Tag> children;
    protected Tag parent;

    protected static final String TEXT_NODE_NAME = "##TEXT";
    protected static final String HTML_COMMENT_NODE_NAME = "##HTML-COMMENT";
    protected static final String JSP_COMMENT_NODE_NAME = "##JSP-COMMENT";
    protected static final String JSP_DIRECTIVE_NODE_NAME = "##JSP-DIRECTIVE";

    public static Tag createRoot () {
        return new Tag ("#ROOT");
    }

    public Tag (String name) {
        if (name.indexOf (":") > 0) {
            String[] temp = name.split (":");
            prefix    = temp [0];
            this.name = temp [1];
        } else {
            this.name = name;
        }
    }

    public String getPrefix () {
        return prefix;
    }

    public String getName () {
        return name;
    }

    public Tag getParent () {
        return parent;
    }

    public int getAttributeCount () {
        return attributes == null ? 0 : attributes.size ();
    }

    public Map<String, String> getAttributes () {
        return attributes;
    }

    public String[] getAttributeNames () {
        if (attributes == null || attributes.size () == 0) return null;
        ArrayList<String> list = new ArrayList<String> ();
        for (String o : attributes.keySet ()) list.add (o);
        String[] names = new String [list.size ()];
        return list.toArray (names);
    }

    public void setAttribute (String name, String value) {
        if (attributes == null)
            attributes = new HashMap<String, String> ();
        if (attributesIgnoreCase == null)
            attributesIgnoreCase = new HashMap<String, String> ();
        attributes.put (name, value);
        attributesIgnoreCase.put (name.toUpperCase (), value);
    }

    public String getAttribute (String name) {
        return attributesIgnoreCase == null ? null : attributesIgnoreCase.get (name.toUpperCase ());
    }

    public void addChild (Tag tag) {
        if (children == null) children = new ArrayList<Tag> ();
        children.add (tag);
        tag.parent = this;
    }

    public Tag[] getChildren () {
        if (children == null) return null;
        Tag[] tags = new Tag [children.size ()];
        return children.toArray (tags);
    }

    public Tag[] getChildren (String name) {
        if (children == null) return null;
        ArrayList<Tag> list = new ArrayList<Tag> ();
        for (Tag tag : children) {
            if (name.equalsIgnoreCase (tag.name))
                list.add (tag);
        }

        if (list.size () == 0) return null;
        Tag[] tags = new Tag [list.size ()];
        return list.toArray (tags);
    }

    public boolean isEmptyTag () {
        return prefix == null && TagUtil.isEmptyTag (name);
    }

    public boolean isBlockTag () {
        return TagUtil.isBlockTag (name);
    }

    public boolean isOptionalTag () {
        return TagUtil.isOptionalTag (name);
    }

    public boolean isTextNode () {
        return TEXT_NODE_NAME.equalsIgnoreCase (name);
    }

    public boolean isHTMLComment () {
        return HTML_COMMENT_NODE_NAME.equalsIgnoreCase (name);
    }

    public boolean isJSPComment () {
        return JSP_COMMENT_NODE_NAME.equalsIgnoreCase (name);
    }

    public boolean isJSPDirective () {
        return JSP_DIRECTIVE_NODE_NAME.equalsIgnoreCase (name);
    }

    public boolean isComment () {
        return isHTMLComment () || isJSPComment ();
    }

    public void removeChild (Tag child) {
        if (this.children != null && children.size () > 0)
            children.remove (child);
    }

    public void clearChild () {
        if (this.children != null) children.clear ();
    }

    public String toString () {
        StringBuffer sb = new StringBuffer ();
        if (!isRoot ()) {
            sb.append ("<").append (name);
            if (attributes != null && attributes.size () > 0) {
                for (String attrName : attributes.keySet ()) {
                    sb.append (" ").append (attrName).append ("=\"").append (attributes.get (attrName)).append ("\"");
                }
            }
            if (isEmptyTag () || (!hasChild () && !TagUtil.isOptionalTag (name))) sb.append ("/>");
            else
                sb.append (">");
        }
        if (hasChild ()) {
            for (Tag tag : children) {
                sb.append (tag);
            }
        }
        if (!isRoot () && !isEmptyTag ()/* && (hasChild () || TagUtil.isMustCloseTag (name))*/)
            sb.append ("</").append (name).append (">");

        return sb.toString ();
    }

    private boolean isRoot () {
        return name.equalsIgnoreCase ("#ROOT");
    }

    private boolean hasChild () {
        return children != null && children.size () > 0;
    }
}